const OSS = require('ali-oss');
const path = require('path');
const fs = require('fs');
const mp3Duration = require('mp3-duration');
const sharp = require('sharp');

class OSSManager {
  constructor() {
    this.client = new OSS({
      region: 'oss-ap-northeast-1',
      accessKeyId: 'LTAI5tNwqYAFseP5L9homYyf',
      accessKeySecret: '467c2AVvztEcAKuT2oTAwJ4UjklmyT',
      bucket: 'knowmeh5',
      endpoint: 'oss-ap-northeast-1.aliyuncs.com',
      secure: true
    });
    
    this.customDomain = 'https://www.knomi.me';
    this.ossDomain = 'https://knowmeh5.oss-ap-northeast-1.aliyuncs.com';
    
    // 设置基础路径前缀，所有操作都将在此目录下进行
    this.basePrefix = 'resource_AiPersion/';
  }

  /**
   * 获取完整的OSS路径（添加基础前缀）
   * @param {string} relativePath - 相对路径
   * @returns {string} - 完整的OSS路径
   */
  getFullPath(relativePath = '') {
    if (!relativePath) return this.basePrefix;
    // 确保不会重复添加基础前缀
    if (relativePath.startsWith(this.basePrefix)) {
      return relativePath;
    }
    return this.basePrefix + relativePath;
  }

  /**
   * 从完整路径中移除基础前缀，获取相对路径
   * @param {string} fullPath - 完整路径
   * @returns {string} - 相对路径
   */
  getRelativePath(fullPath) {
    if (fullPath.startsWith(this.basePrefix)) {
      return fullPath.substring(this.basePrefix.length);
    }
    return fullPath;
  }

  /**
   * 创建文件夹
   * @param {string} folderName - 文件夹名称（相对于resource_AiPersion目录）
   * @returns {Promise<Object>} - 操作结果
   */
  async createFolder(folderName) {
    try {
      // 确保文件夹名称以 / 结尾
      const folderPath = folderName.endsWith('/') ? folderName : `${folderName}/`;
      const fullFolderPath = this.getFullPath(folderPath);
      
      const result = await this.client.put(fullFolderPath, Buffer.from(''));
      
      console.log(`文件夹创建成功: ${this.basePrefix}${folderName}`);
      return { 
        success: true, 
        folderName: folderName,
        path: folderPath,
        fullPath: fullFolderPath,
        message: '文件夹创建成功'
      };
    } catch (error) {
      console.error('创建文件夹失败:', error);
      return { 
        success: false, 
        error: error.message,
        message: '文件夹创建失败'
      };
    }
  }

  /**
   * 获取文件夹列表
   * @param {string} prefix - 前缀路径（相对于resource_AiPersion目录）
   * @param {number} retries - 重试次数，默认3次
   * @returns {Promise<Object>} - 文件夹列表
   */
  async getFolderList(prefix = '', retries = 3) {
    let lastError;
    
    for (let attempt = 1; attempt <= retries; attempt++) {
      try {
        const fullPrefix = this.getFullPath(prefix);
        
        // 设置超时时间
        const timeoutPromise = new Promise((_, reject) => {
          setTimeout(() => reject(new Error('请求超时')), 10000); // 10秒超时
        });
        
        const listPromise = this.client.list({
          prefix: fullPrefix,
          delimiter: '/',
          'max-keys': 1000
        });
        
        const result = await Promise.race([listPromise, timeoutPromise]);
        
        // 提取文件夹名称（去掉末尾的 /，并移除基础前缀）
        const folders = (result.prefixes || []).map(folder => {
          const relativeFolderPath = this.getRelativePath(folder);
          const folderName = relativeFolderPath.replace(/\/$/, '');
          return {
            name: folderName,
            path: relativeFolderPath,
            fullPath: folder,
            displayName: folderName.split('/').pop() // 只显示最后一级文件夹名
          };
        });
        
        console.log(`获取到 ${folders.length} 个文件夹（在 ${this.basePrefix} 目录下）`);
        return { 
          success: true, 
          folders: folders,
          count: folders.length,
          basePrefix: this.basePrefix,
          message: '获取文件夹列表成功'
        };
      } catch (error) {
        lastError = error;
        console.error(`获取文件夹列表失败 (尝试 ${attempt}/${retries}):`, error.message);
        
        if (attempt < retries) {
          // 等待后重试，使用指数退避策略
          const delay = Math.pow(2, attempt - 1) * 1000; // 1s, 2s, 4s...
          console.log(`${delay/1000}秒后重试...`);
          await new Promise(resolve => setTimeout(resolve, delay));
        }
      }
    }
    
    console.error('获取文件夹列表最终失败:', lastError);
    return { 
      success: false, 
      error: lastError.message,
      message: `获取文件夹列表失败 (已重试${retries}次)`
    };
  }

  /**
   * 获取文件夹内容
   * @param {string} folderName - 文件夹名称（相对于resource_AiPersion目录）
   * @returns {Promise<Object>} - 文件夹内容
   */
  async getFolderContents(folderName) {
    try {
      const folderPrefix = folderName.endsWith('/') ? folderName : `${folderName}/`;
      const fullFolderPrefix = this.getFullPath(folderPrefix);
      
      const result = await this.client.list({
        prefix: fullFolderPrefix,
        delimiter: '/',
        'max-keys': 1000
      });
      
      // 子文件夹
      const subFolders = (result.prefixes || [])
        .filter(folder => folder !== fullFolderPrefix)
        .map(folder => {
          const relativeFolderPath = this.getRelativePath(folder);
          return {
            name: relativeFolderPath.replace(/\/$/, ''),
            path: relativeFolderPath,
            fullPath: folder,
            displayName: relativeFolderPath.replace(folderPrefix, '').replace(/\/$/, '')
          };
        });
      
      // 文件列表（排除文件夹标识符）
      const files = (result.objects || [])
        .filter(obj => !obj.name.endsWith('/') && obj.name !== fullFolderPrefix.slice(0, -1))
        .map(obj => {
          const relativePath = this.getRelativePath(obj.name);
          return {
            name: relativePath,
            fullPath: obj.name,
            fileName: path.basename(obj.name),
            size: obj.size,
            lastModified: obj.lastModified,
            ossUrl: obj.url,
            customUrl: this.convertToCustomDomain(obj.url),
            type: this.getFileType(obj.name)
          };
        });
      
      console.log(`文件夹 ${this.basePrefix}${folderName} 包含 ${subFolders.length} 个子文件夹和 ${files.length} 个文件`);
      return {
        success: true,
        folderName: folderName,
        fullFolderName: this.basePrefix + folderName,
        subFolders: subFolders,
        files: files,
        totalItems: subFolders.length + files.length,
        message: '获取文件夹内容成功'
      };
    } catch (error) {
      console.error('获取文件夹内容失败:', error);
      return { 
        success: false, 
        error: error.message,
        message: '获取文件夹内容失败'
      };
    }
  }

  /**
   * 上传文件到指定文件夹
   * @param {string} localPath - 本地文件路径
   * @param {string} folderName - 目标文件夹名称（相对于resource_AiPersion目录）
   * @param {string} customFileName - 自定义文件名（可选）
   * @returns {Promise<Object>} - 上传结果
   */
  async uploadFileToFolder(localPath, folderName, customFileName = null) {
    try {
      const filename = customFileName || path.basename(localPath);
      const folderPrefix = folderName.endsWith('/') ? folderName : `${folderName}/`;
      const relativePath = `${folderPrefix}${filename}`;
      const fullOssPath = this.getFullPath(relativePath);
      
      // 检查文件是否存在
      if (!fs.existsSync(localPath)) {
        throw new Error('本地文件不存在');
      }
      
      // 上传文件到指定文件夹
      const result = await this.client.put(fullOssPath, localPath);
      const customUrl = this.convertToCustomDomain(result.url);
      
      // 删除临时文件（如果是uploads目录下的临时文件）
      if (localPath.includes('uploads' + path.sep) || localPath.includes('uploads/')) {
        try {
          fs.unlinkSync(localPath);
          console.log('临时文件已删除:', localPath);
        } catch (unlinkError) {
          console.warn('删除临时文件失败:', unlinkError.message);
        }
      }
      
      console.log(`文件上传成功: ${fullOssPath}`);
      return {
        success: true,
        ossUrl: result.url,
        customUrl: customUrl,
        folderName: folderName,
        fileName: filename,
        ossPath: relativePath,
        fullOssPath: fullOssPath,
        message: '文件上传成功'
      };
    } catch (error) {
      console.error('上传文件失败:', error);
      return { 
        success: false, 
        error: error.message,
        message: '文件上传失败'
      };
    }
  }

  /**
   * 上传文件到根目录指定文件夹（不添加resource_AiPersion前缀）
   * @param {string} localPath - 本地文件路径
   * @param {string} folderName - 目标文件夹名称（相对于OSS根目录）
   * @param {string} customFileName - 自定义文件名（可选）
   * @returns {Promise<Object>} - 上传结果
   */
  async uploadFileToRootFolder(localPath, folderName, customFileName = null) {
    try {
      const filename = customFileName || path.basename(localPath);
      const folderPrefix = folderName.endsWith('/') ? folderName : `${folderName}/`;
      const ossPath = `${folderPrefix}${filename}`;
      
      // 检查文件是否存在
      if (!fs.existsSync(localPath)) {
        throw new Error('本地文件不存在');
      }
      
      // 上传文件到指定文件夹（直接使用ossPath，不添加basePrefix）
      const result = await this.client.put(ossPath, localPath);
      const customUrl = this.convertToCustomDomain(result.url);
      
      // 删除临时文件（如果是uploads目录下的临时文件）
      if (localPath.includes('uploads' + path.sep) || localPath.includes('uploads/')) {
        try {
          fs.unlinkSync(localPath);
          console.log('临时文件已删除:', localPath);
        } catch (unlinkError) {
          console.warn('删除临时文件失败:', unlinkError.message);
        }
      }
      
      console.log(`文件上传成功: ${ossPath}`);
      return {
        success: true,
        ossUrl: result.url,
        customUrl: customUrl,
        folderName: folderName,
        fileName: filename,
        ossPath: ossPath,
        fullOssPath: ossPath, // 对于根目录上传，fullOssPath就是ossPath
        message: '文件上传成功'
      };
    } catch (error) {
      console.error('上传文件失败:', error);
      return { 
        success: false, 
        error: error.message,
        message: '文件上传失败'
      };
    }
  }

  /**
   * 批量上传文件到指定文件夹
   * @param {Array} fileList - 文件路径列表
   * @param {string} folderName - 目标文件夹名称（相对于resource_AiPersion目录）
   * @returns {Promise<Array>} - 上传结果列表
   */
  async uploadMultipleFiles(fileList, folderName) {
    const results = [];
    
    for (let i = 0; i < fileList.length; i++) {
      const filePath = fileList[i];
      try {
        console.log(`正在上传第 ${i + 1}/${fileList.length} 个文件: ${path.basename(filePath)}`);
        const result = await this.uploadFileToFolder(filePath, folderName);
        results.push(result);
      } catch (error) {
        results.push({
          success: false,
          filePath: filePath,
          error: error.message,
          message: `文件 ${path.basename(filePath)} 上传失败`
        });
      }
    }
    
    const successCount = results.filter(r => r.success).length;
    console.log(`批量上传完成: ${successCount}/${fileList.length} 个文件上传成功（在 ${this.basePrefix} 目录下）`);
    
    return {
      results: results,
      total: fileList.length,
      success: successCount,
      failed: fileList.length - successCount
    };
  }

  /**
   * 获取音频时长
   * @param {Buffer} audioBuffer - 音频数据Buffer
   * @returns {Promise<number|null>} - 音频时长（秒）
   */
  async getAudioDuration(audioBuffer) {
    return new Promise((resolve) => {
      try {
        // mp3-duration 需要一个临时文件
        const tempDir = path.join(__dirname, '../../temp');
        if (!fs.existsSync(tempDir)) {
          fs.mkdirSync(tempDir, { recursive: true });
        }
        
        const tempFilePath = path.join(tempDir, `temp_${Date.now()}.mp3`);
        fs.writeFileSync(tempFilePath, audioBuffer);
        
        mp3Duration(tempFilePath, (err, duration) => {
          // 清理临时文件
          try {
            if (fs.existsSync(tempFilePath)) {
              fs.unlinkSync(tempFilePath);
            }
          } catch (cleanupError) {
            console.warn('清理临时文件失败:', cleanupError.message);
          }
          
          if (err) {
            console.warn('获取音频时长失败:', err.message);
            resolve(null);
          } else {
            resolve(duration);
          }
        });
      } catch (error) {
        console.warn('获取音频时长失败:', error.message);
        resolve(null);
      }
    });
  }

  /**
   * 上传base64编码的音频数据到Voice文件夹
   * @param {string} base64Data - base64编码的音频数据
   * @param {string} fileName - 文件名（可选，如果不提供将自动生成）
   * @returns {Promise<Object>} - 上传结果
   */
  async uploadBase64Audio(base64Data, fileName = null) {
    try {
      if (!base64Data) {
        throw new Error('base64音频数据不能为空');
      }

      // 生成文件名（如果没有提供）
      const timestamp = Date.now();
      const finalFileName = fileName || `audio_${timestamp}.mp3`;
      
      // 确保Voice文件夹路径
      const voiceFolderPath = 'Ai_persion/Voice/';
      const audioPath = `${voiceFolderPath}${finalFileName}`;
      const fullOssPath = this.getFullPath(audioPath);
      
      // 将base64数据转换为Buffer
      const audioBuffer = Buffer.from(base64Data, 'base64');
      
      // 获取音频时长（直接从Buffer获取，不需要临时文件）
      const duration = await this.getAudioDuration(audioBuffer);
      
      // 上传到OSS
      const result = await this.client.put(fullOssPath, audioBuffer, {
        headers: {
          'Content-Type': 'audio/mpeg',
          'Cache-Control': 'public, max-age=31536000'
        }
      });
      
      const customUrl = this.convertToCustomDomain(result.url);
      
      console.log(`Base64音频上传成功: ${fullOssPath}`);
      console.log(`音频访问URL: ${customUrl}`);
      if (duration !== null) {
        console.log(`音频时长: ${duration.toFixed(2)}秒`);
      }
      
      return {
        success: true,
        ossUrl: result.url,
        customUrl: customUrl,
        folderName: 'Ai_persion/Voice',
        fileName: finalFileName,
        ossPath: audioPath,
        fullOssPath: fullOssPath,
        fileSize: audioBuffer.length,
        duration: duration, // 添加音频时长
        message: 'Base64音频上传成功'
      };
    } catch (error) {
      console.error('上传Base64音频失败:', error);
      return { 
        success: false, 
        error: error.message,
        message: 'Base64音频上传失败'
      };
    }
  }

  /**
   * 通过URL下载图片并上传到Images文件夹（支持webp转换和压缩）
   * @param {string} imageUrl - 图片URL地址
   * @param {string} fileName - 文件名（可选，如果不提供将自动生成）
   * @param {string} taskId - 任务ID（可选，用于更新数据库记录）
   * @param {Object} options - 转换选项（可选）
   * @param {boolean} options.convertToWebp - 是否转换为webp格式，默认true
   * @param {number} options.quality - 压缩质量(1-100)，默认80
   * @param {number} options.width - 图片宽度（可选）
   * @param {number} options.height - 图片高度（可选）
   * @returns {Promise<Object>} - 上传结果
   */
  async uploadImageFromUrl(imageUrl, fileName = null, taskId = null, options = {}) {
    try {
      if (!imageUrl) {
        throw new Error('图片URL不能为空');
      }

      // 设置默认选项
      const {
        convertToWebp = true,
        quality = 80,
        width = null,
        height = null
      } = options;

      // 验证质量参数
      if (quality < 1 || quality > 100) {
        throw new Error('压缩质量必须在1-100之间');
      }

      // 验证URL格式
      let url;
      try {
        url = new URL(imageUrl);
      } catch (urlError) {
        throw new Error('无效的图片URL格式');
      }

      // 动态导入axios（如果需要）
      const axios = require('axios');
      
      // 下载图片
      console.log(`开始下载图片: ${imageUrl}`);
      const response = await axios({
        method: 'GET',
        url: imageUrl,
        responseType: 'arraybuffer',
        timeout: 30000, // 30秒超时
        headers: {
          'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
        }
      });

      // 检查响应
      if (!response.data) {
        throw new Error('下载的图片数据为空');
      }

      const originalImageBuffer = Buffer.from(response.data);
      
      // 检查原始文件大小（限制为20MB，因为下载后可能会压缩）
      if (originalImageBuffer.length > 20 * 1024 * 1024) {
        throw new Error('图片文件过大，最大支持20MB');
      }

      // 检查是否为图片格式（简单检查）
      const contentType = response.headers['content-type'] || '';
      if (!contentType.startsWith('image/')) {
        throw new Error('URL指向的不是图片文件');
      }

      console.log(`原始图片大小: ${(originalImageBuffer.length / 1024).toFixed(2)} KB`);

      // 使用Sharp处理图片
      let sharpInstance = sharp(originalImageBuffer);
      
      // 获取图片信息
      const metadata = await sharpInstance.metadata();
      console.log(`原始图片尺寸: ${metadata.width}x${metadata.height}, 格式: ${metadata.format}`);

      // 调整尺寸（如果指定了宽度或高度）
      if (width || height) {
        sharpInstance = sharpInstance.resize(width, height, {
          fit: 'inside',
          withoutEnlargement: true
        });
        console.log(`调整图片尺寸到: ${width || 'auto'}x${height || 'auto'}`);
      }

      let processedImageBuffer;
      let finalFileExtension;
      let finalContentType;

      if (convertToWebp) {
        // 转换为WebP格式
        processedImageBuffer = await sharpInstance
          .webp({ quality: quality })
          .toBuffer();
        finalFileExtension = '.webp';
        finalContentType = 'image/webp';
        console.log(`转换为WebP格式，质量: ${quality}%`);
      } else {
        // 保持原格式但进行压缩
        const originalFormat = metadata.format;
        if (originalFormat === 'jpeg' || originalFormat === 'jpg') {
          processedImageBuffer = await sharpInstance
            .jpeg({ quality: quality })
            .toBuffer();
          finalFileExtension = '.jpg';
          finalContentType = 'image/jpeg';
        } else if (originalFormat === 'png') {
          processedImageBuffer = await sharpInstance
            .png({ quality: quality })
            .toBuffer();
          finalFileExtension = '.png';
          finalContentType = 'image/png';
        } else if (originalFormat === 'webp') {
          processedImageBuffer = await sharpInstance
            .webp({ quality: quality })
            .toBuffer();
          finalFileExtension = '.webp';
          finalContentType = 'image/webp';
        } else {
          // 对于其他格式，转换为JPEG
          processedImageBuffer = await sharpInstance
            .jpeg({ quality: quality })
            .toBuffer();
          finalFileExtension = '.jpg';
          finalContentType = 'image/jpeg';
        }
        console.log(`保持${originalFormat}格式，质量: ${quality}%`);
      }

      // 检查处理后的文件大小（限制为10MB）
      if (processedImageBuffer.length > 10 * 1024 * 1024) {
        throw new Error('处理后的图片文件过大，请降低质量或尺寸');
      }

      console.log(`处理后图片大小: ${(processedImageBuffer.length / 1024).toFixed(2)} KB`);
      console.log(`压缩率: ${((1 - processedImageBuffer.length / originalImageBuffer.length) * 100).toFixed(2)}%`);

      // 生成文件名
      const timestamp = Date.now();
      let finalFileName = fileName || `image_${timestamp}`;
      
      // 确保文件名有正确的扩展名
      if (!finalFileName.includes('.')) {
        finalFileName = finalFileName + finalFileExtension;
      } else {
        // 如果提供了文件名，但格式不匹配，则替换扩展名
        const nameWithoutExt = finalFileName.replace(/\.[^/.]+$/, '');
        finalFileName = nameWithoutExt + finalFileExtension;
      }

      // 确保Images文件夹路径
      const imagesFolderPath = 'Ai_persion/Images/';
      const imagePath = `${imagesFolderPath}${finalFileName}`;
      const fullOssPath = this.getFullPath(imagePath);

      // 上传到OSS
      const result = await this.client.put(fullOssPath, processedImageBuffer, {
        headers: {
          'Content-Type': finalContentType,
          'Cache-Control': 'public, max-age=31536000'
        }
      });

      const customUrl = this.convertToCustomDomain(result.url);

      console.log(`图片处理并上传成功: ${fullOssPath}`);
      console.log(`原始图片URL: ${imageUrl}`);
      console.log(`OSS访问URL: ${customUrl}`);
      console.log(`处理选项: 转换WebP=${convertToWebp}, 质量=${quality}%, 尺寸=${width || 'auto'}x${height || 'auto'}`);
      if (taskId) {
        console.log(`任务ID: ${taskId}`);
      }

      return {
        success: true,
        ossUrl: result.url,
        customUrl: customUrl,
        folderName: 'Ai_persion/Images',
        fileName: finalFileName,
        ossPath: imagePath,
        fullOssPath: fullOssPath,
        fileSize: processedImageBuffer.length,
        originalSize: originalImageBuffer.length,
        compressionRatio: ((1 - processedImageBuffer.length / originalImageBuffer.length) * 100).toFixed(2),
        originalUrl: imageUrl,
        contentType: finalContentType,
        taskId: taskId,
        processOptions: {
          convertToWebp,
          quality,
          width,
          height,
          originalFormat: metadata.format,
          finalFormat: finalFileExtension.substring(1)
        },
        message: '图片处理并上传成功'
      };
    } catch (error) {
      console.error('图片处理上传失败:', error);
      return { 
        success: false, 
        error: error.message,
        message: '图片处理上传失败'
      };
    }
  }

  /**
   * 删除文件
   * @param {string} ossPath - OSS文件路径（相对于resource_AiPersion目录）
   * @returns {Promise<Object>} - 删除结果
   */
  async deleteFile(ossPath) {
    try {
      const fullOssPath = this.getFullPath(ossPath);
      await this.client.delete(fullOssPath);
      console.log(`文件删除成功: ${fullOssPath}`);
      return { 
        success: true, 
        deletedPath: ossPath,
        fullDeletedPath: fullOssPath,
        message: '文件删除成功'
      };
    } catch (error) {
      console.error('删除文件失败:', error);
      return { 
        success: false, 
        error: error.message,
        message: '删除文件失败'
      };
    }
  }

  /**
   * 删除文件夹及其所有内容
   * @param {string} folderName - 文件夹名称（相对于resource_AiPersion目录）
   * @returns {Promise<Object>} - 删除结果
   */
  async deleteFolder(folderName) {
    try {
      const folderPrefix = folderName.endsWith('/') ? folderName : `${folderName}/`;
      const fullFolderPrefix = this.getFullPath(folderPrefix);
      
      // 获取文件夹中的所有文件
      const listResult = await this.client.list({
        prefix: fullFolderPrefix,
        'max-keys': 1000
      });
      
      if (listResult.objects && listResult.objects.length > 0) {
        // 批量删除文件
        const objectsToDelete = listResult.objects.map(obj => obj.name);
        await this.client.deleteMulti(objectsToDelete.slice(0, 1000)); // OSS限制每次最多删除1000个对象
        
        console.log(`文件夹删除成功: ${fullFolderPrefix} (删除了 ${objectsToDelete.length} 个对象)`);
        return { 
          success: true, 
          deletedFolder: folderName,
          fullDeletedFolder: fullFolderPrefix,
          deletedCount: objectsToDelete.length,
          message: `文件夹删除成功，共删除 ${objectsToDelete.length} 个文件`
        };
      } else {
        console.log(`文件夹 ${fullFolderPrefix} 为空或不存在`);
        return { 
          success: true, 
          deletedFolder: folderName,
          fullDeletedFolder: fullFolderPrefix,
          deletedCount: 0,
          message: '文件夹为空或不存在'
        };
      }
    } catch (error) {
      console.error('删除文件夹失败:', error);
      return { 
        success: false, 
        error: error.message,
        message: '删除文件夹失败'
      };
    }
  }

  /**
   * 转换为自定义域名URL
   * @param {string} ossUrl - OSS URL
   * @returns {string} - 自定义域名URL
   */
  convertToCustomDomain(ossUrl) {
    if (!ossUrl) return null;
    return ossUrl.replace(this.ossDomain, this.customDomain);
  }

  /**
   * 检查文件是否存在
   * @param {string} ossPath - OSS文件路径（相对于resource_AiPersion目录）
   * @returns {Promise<boolean>} - 文件是否存在
   */
  async fileExists(ossPath) {
    try {
      const fullOssPath = this.getFullPath(ossPath);
      await this.client.head(fullOssPath);
      return true;
    } catch (error) {
      if (error.code === 'NoSuchKey') {
        return false;
      }
      throw error;
    }
  }

  /**
   * 获取文件信息
   * @param {string} ossPath - OSS文件路径（相对于resource_AiPersion目录）
   * @returns {Promise<Object>} - 文件信息
   */
  async getFileInfo(ossPath) {
    try {
      const fullOssPath = this.getFullPath(ossPath);
      const result = await this.client.head(fullOssPath);
      return {
        success: true,
        ossPath: ossPath,
        fullOssPath: fullOssPath,
        fileInfo: {
          size: result.res.headers['content-length'],
          type: result.res.headers['content-type'],
          lastModified: result.res.headers['last-modified'],
          etag: result.res.headers.etag
        }
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }

  /**
   * 根据文件扩展名获取文件类型
   * @param {string} fileName - 文件名
   * @returns {string} - 文件类型
   */
  getFileType(fileName) {
    const ext = path.extname(fileName).toLowerCase();
    const imageExts = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg'];
    const videoExts = ['.mp4', '.avi', '.mov', '.wmv', '.flv', '.webm'];
    const audioExts = ['.mp3', '.wav', '.flac', '.aac', '.ogg'];
    const docExts = ['.pdf', '.doc', '.docx', '.txt', '.rtf'];
    
    if (imageExts.includes(ext)) return 'image';
    if (videoExts.includes(ext)) return 'video';
    if (audioExts.includes(ext)) return 'audio';
    if (docExts.includes(ext)) return 'document';
    return 'other';
  }

  /**
   * 生成预签名URL（用于临时访问私有文件）
   * @param {string} ossPath - OSS文件路径（相对于resource_AiPersion目录）
   * @param {number} expires - 过期时间（秒）
   * @returns {Promise<string>} - 预签名URL
   */
  async generatePresignedUrl(ossPath, expires = 3600) {
    try {
      const fullOssPath = this.getFullPath(ossPath);
      const url = this.client.signatureUrl(fullOssPath, { expires: expires });
      return { 
        success: true, 
        url: url,
        ossPath: ossPath,
        fullOssPath: fullOssPath,
        expires: expires
      };
    } catch (error) {
      return { success: false, error: error.message };
    }
  }
}

// 导出单例实例
module.exports = new OSSManager(); 